package edu.cmu.cs211.exprtree.ast;

import java.math.BigDecimal;
import java.util.Map;

/** Represents negation, for example -x */
public final class NegationExpression extends UnaryExpression {
	// field
	Expression operand;
	
	// constructor
	public NegationExpression(Expression operand) {
		super(operand);
		this.operand = operand;
	}

	/*  NegationExpression.evaluate: replaces the variable with the value in hashmap
	 *  and evaluate the expression
	 *  returns a BigDecimal value of the expression
	 */
	public BigDecimal evaluate(Map<String, BigDecimal> variableAssignments) {
		// recurse until the leaf node then start evaluating
		if(operand != null)
		{
			operand = new ConstantExpression(operand.evaluate(variableAssignments));
			
		}
		String key = null;
		
		// throws an NullPointerException if map is required and is empty
		if(variableAssignments == null && (operand.getClass().equals(VariableExpression.class)))
			throw new NullPointerException();
	
		
		// x
		if(operand.getClass().equals(VariableExpression.class))
		{
			if(variableAssignments.containsKey(key = ((VariableExpression)operand).getName()))
			{
				return variableAssignments.get(key);
			}
			else
				throw new IllegalArgumentException();
		}
		
		// c1 - constant
		return (new BigDecimal(0) ).subtract( ((ConstantExpression)operand).getValue() );	
	}

	/**
	 * Constant folds this operator. The only rule for negation is that if you
	 * have -(constant) you return a new constant with negative the value of the
	 * constant
	 */
	public Expression cfold() {
		// recurse until the leaf node and start folding
		if(operand != null)
		{
			operand = operand.cfold();
		}
		
		// - (constant)
		if(operand.getClass().equals(ConstantExpression.class))
		{
			return new ConstantExpression((new BigDecimal(0) ).subtract( ((ConstantExpression)operand).getValue() ));	
		}
		// - (expression)
		return new NegationExpression(operand);
	}

	/** The minus sign `-' */
	@Override
	public char getOperatorSymbol() {
		return '-';
	}
}
